dataviz\figure\figuretypes/
histogram.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use crate::figure::configuration::figureconfig::FigureConfig;

/// Represents a histogram, including title, axis labels, bin configuration, and cached data.
pub struct Histogram {
    /// Title of the histogram.
    pub title: String,
    /// Label for the X-axis.
    pub x_label: String,
    /// Label for the Y-axis.
    pub y_label: String,
    /// Number of bins in the histogram.
    pub bins: usize,
    /// Raw data values to be represented in the histogram.
    pub data: Vec<f64>,
    /// Color of the histogram bars in RGB format.
    pub color: [u8; 3],
    /// Cached minimum value in the dataset.
    pub min: f64,
    /// Cached maximum value in the dataset.
    pub max: f64,
    /// Cached frequencies for each bin.
    pub bin_counts: Vec<f64>,
    /// Cached width of each bin.
    pub bin_width: f64,
    /// Configuration settings for rendering the histogram.
    pub config: FigureConfig,
}

impl Histogram {
    /// Creates a new `Histogram` instance with the specified configuration.
    ///
    /// # Parameters
    /// - `title`: The title of the histogram.
    /// - `x_label`: The label for the X-axis.
    /// - `y_label`: The label for the Y-axis.
    /// - `bins`: The number of bins in the histogram.
    /// - `color`: The RGB color of the histogram bars.
    /// - `config`: The `FigureConfig` containing appearance and behavior settings.
    ///
    /// # Returns
    /// A new `Histogram` instance with empty data and initialized bins.
    ///
    /// # Example
    /// ```rust
    /// use crate::figure::configuration::figureconfig::FigureConfig;
    /// use crate::figure::histogram::Histogram;
    ///
    /// let config = FigureConfig::default();
    /// let histogram = Histogram::new("Data Distribution", "Values", "Frequency", 10, [255, 0, 0], config);
    /// ```
    pub fn new(
        title: &str,
        x_label: &str,
        y_label: &str,
        bins: usize,
        color: [u8; 3],
        config: FigureConfig,
    ) -> Self {
        Self {
            title: title.to_string(),
            x_label: x_label.to_string(),
            y_label: y_label.to_string(),
            bins,
            data: Vec::new(),
            color,
            min: f64::INFINITY,
            max: f64::NEG_INFINITY,
            bin_counts: vec![0.0; bins],
            bin_width: 0.0,
            config,
        }
    }

    /// Adds multiple data values to the histogram.
    ///
    /// # Parameters
    /// - `values`: A vector of `f64` values to be added to the histogram.
    ///
    /// # Example
    /// ```rust
    /// histogram.add_data_vec(vec![1.2, 2.5, 3.1, 4.8]);
    /// ```
    pub fn add_data_vec(&mut self, values: Vec<f64>) {
        for value in values {
            self.add_data(value);
        }
    }

    /// Adds a single data value to the histogram.
    ///
    /// # Parameters
    /// - `value`: An `f64` value to be added to the histogram.
    ///
    /// # Details
    /// - Updates the cached minimum and maximum values.
    /// - Recalculates the bin width.
    /// - Updates the appropriate bin count based on the value.
    ///
    /// # Example
    /// ```rust
    /// histogram.add_data(3.5);
    /// ```
    pub fn add_data(&mut self, value: f64) {
        self.data.push(value);

        // Update min and max
        if value < self.min {
            self.min = value;
        }
        if value > self.max {
            self.max = value;
        }

        // Recalculate bin width and update bin counts
        self.bin_width = (self.max - self.min) / self.bins as f64;
        if self.bin_width > 0.0 {
            let bin_index = ((value - self.min) / self.bin_width).floor() as usize;
            if bin_index < self.bins {
                self.bin_counts[bin_index] += 1.0;
            }
        }
    }

    /// Calculates the bin ranges and frequencies for the histogram.
    ///
    /// # Returns
    /// A vector of tuples where each tuple contains:
    /// - The starting value of the bin.
    /// - The frequency count for that bin.
    ///
    /// # Example
    /// ```rust
    /// let bins = histogram.calculate_bins();
    /// for (start, count) in bins {
    ///     println!("Bin starts at {}, count is {}", start, count);
    /// }
    /// ```
    pub fn calculate_bins(&self) -> Vec<(f64, f64)> {
        self.bin_counts
            .iter()
            .enumerate()
            .map(|(i, &freq)| (self.min + i as f64 * self.bin_width, freq))
            .collect()
    }
}